package com.afdor.rws.event.driven.support.channel.producer.transaction.impl;

import com.afdor.rws.annotation.extension.Extension;
import com.afdor.rws.event.driven.api.channel.producer.EventProducer;
import com.afdor.rws.event.driven.api.channel.producer.transaction.EventProducerTransactionItem;
import com.afdor.rws.event.driven.entities.Event;
import lombok.Getter;
import lombok.NonNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 默认执行通道事物管理模式
 *
 * @author 悭梵
 * @date Created in 2018-12-17 16:32
 */
@Extension(value = "default,local", order = Extension.NORMAL_ORDER - 100, scope = Extension.Scope.PROTOTYPE, interfaceClass = EventProducerTransactionItem.class)
public class DefaultEventProducerTransactionItemImpl implements EventProducerTransactionItem {

    @Getter
    private final EventProducer eventProducer;

    @Getter
    private final String transactionId;

    @Getter
    private volatile List<Event> eventList;

    public DefaultEventProducerTransactionItemImpl(@NonNull final String transactionId, @NonNull final EventProducer eventProducer) {
        this.eventProducer = eventProducer;
        // 获取配置的Id生成策略
        this.transactionId = transactionId;
    }

    @Override
    public synchronized void addEvent(@NonNull Event event) {
        if (this.eventList == null) {
            this.eventList = new ArrayList<>(10);
        }
        this.eventList.add(event);
        event.setStatus(Event.Status.JOIN_TRANSACTION);
    }

    @Override
    public synchronized void rollback() {
        Optional.ofNullable(getEventList())
                .orElse(Collections.emptyList())
                .forEach(event -> event.setStatus(Event.Status.ROLLBACK));
    }

    @Override
    public synchronized boolean commit() {
        Optional.ofNullable(getEventList())
                .orElse(Collections.emptyList())
                .forEach(event -> {
                    event.setSendType(Event.SendType.ASYNC_TRANSACTION);
                    event.setStatus(Event.Status.SEND);
                    getEventProducer().sendAsyncEvent(event);
                });
        return Boolean.TRUE;
    }

}
